package hasalah.demo.client.views;


import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapType;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.Maps;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.control.MapTypeControl;
import com.google.gwt.maps.client.control.ScaleControl;
import com.google.gwt.maps.client.event.MarkerDragEndHandler;
import com.google.gwt.maps.client.event.MarkerDragHandler;
import com.google.gwt.maps.client.event.MarkerDragHandler.MarkerDragEvent;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.LatLngBounds;
import com.google.gwt.maps.client.overlay.Icon;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.client.overlay.MarkerOptions;
import com.google.gwt.maps.client.overlay.Polygon;
import com.google.gwt.maps.client.overlay.PolygonOptions;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;

public class CheckinActivityCompsite extends Composite {

	private PolygonII exactPolygon;
	private PolygonII allowablePolygon ;
	final TextBox latTextBox  = new TextBox();
	final TextBox longTextBox = new TextBox();
	final Label finalLongLabel  = new Label();
	final Label finalLatLabel  = new Label();
	final Label whereIsTheManLabel  = new Label();

	
	public CheckinActivityCompsite() {
		
		final FlexTable formTable = new FlexTable();
		initWidget(formTable);
		formTable.addStyleName("cw-FlexTable");
		formTable.setWidth("600px");
		formTable.setCellSpacing(5);
		formTable.setCellPadding(3);
		
		
		// TextBox's
		Label longLabel = new Label("Long: ");
		
		Label latLabel = new Label("Lat: ");
		


		FlexTable customTable = new FlexTable();

		customTable.setWidget(1, 1, longLabel);
		customTable.setWidget(1, 2, longTextBox);
		customTable.setWidget(2, 1, latLabel);
		customTable.setWidget(2, 2, latTextBox);

		customTable.setWidget(2, 2, latTextBox);

		customTable.setWidget(2, 2, latTextBox);

		customTable.setWidget(3, 2, finalLongLabel);

		customTable.setWidget(4, 2, finalLatLabel);
		
		customTable.setWidget(5, 2, whereIsTheManLabel);
	
		formTable.setWidget(2, 1, customTable);
		
		Maps.loadMapsApi("", "2", false, new Runnable() {
			public void run() {
				formTable.setWidget(1, 1, buildUi());
			}
		});
		
		
	}
	
	private MapWidget buildUi() {
		// Open a map centered on Cawker City, KS USA
		LatLng cawkerCity = LatLng.newInstance(39.509, -98.434);
		
		// LatLng saharMullRiyadh = LatLng.newInstance(24.738452,46.682957);

		LatLng kingdomCentreRiyadh = LatLng.newInstance(24.707909399,46.67605876);
		
		LatLng kindomMapCenter = LatLng.newInstance(24.711165,46.674514);
		
		final MapWidget map = new MapWidget(kindomMapCenter, 2);
		map.setSize("100%", "100%");
		// Add some controls for the zoom level
		map.addControl(new LargeMapControl());
		map.addControl(new MapTypeControl());
		map.addControl(new ScaleControl());
		map.setZoomLevel(16);
		map.setCurrentMapType(MapType.getSatelliteMap());


		// Add a marker
		MarkerOptions markerOptions = MarkerOptions.newInstance();

		markerOptions.setDraggable(true);

		MarkerOptions manMarkerOptions = MarkerOptions.newInstance();

		manMarkerOptions.setDraggable(true);
		manMarkerOptions.setIcon(Icon.newInstance("http://maps.google.com/help/maps/streetview/images/flying_man.png"));

		final Marker manMarker = new Marker(kingdomCentreRiyadh,manMarkerOptions);

		manMarker.setDraggingEnabled(true);

		manMarker.setImage("http://maps.google.com/help/maps/streetview/images/flying_man.png");

		manMarker.addMarkerDragHandler(new MarkerDragHandler() {
			
			@Override
			public void onDrag(MarkerDragEvent event) {
		
				map.closeInfoWindow();
				
				
			}
		});
		
		// With in an polygon detection 
		manMarker.addMarkerDragEndHandler(new MarkerDragEndHandler() {
			
			public void onDragEnd(MarkerDragEndEvent event) {
				

				// Checking if the man is in the exact are or not
				if(exactPolygon != null) {
					
					if(exactPolygon.contains(manMarker.getLatLng())) {
						
						whereIsTheManLabel.setText("Man : On the [EXACT] spot !!!");
						
					} else if(allowablePolygon.contains(manMarker.getLatLng())) {
						
						whereIsTheManLabel.setText("Man : On the [ALLOWABLE] spot !!!");
						
					} else {
						
						whereIsTheManLabel.setText("Man : Is OUTSIDE the spot !!!");
					}
					
					
				}
					
				
				finalLongLabel.setText("Man : Long [" + Double.toString(manMarker.getLatLng().getLongitude()) + "]");

				finalLatLabel.setText("Man :   Lat [" + Double.toString(manMarker.getLatLng().getLatitude()) + "]");

				
			}
		});
		

		
		
		final Marker marker = new Marker(kingdomCentreRiyadh,markerOptions);

		marker.setDraggingEnabled(true);

		// Adding a Lat - Long tracking
		marker.addMarkerDragHandler(new MarkerDragHandler() {

			public void onDrag(MarkerDragEvent event) {

				map.closeInfoWindow();
				// TODO
				longTextBox.setText(Double.toString(marker.getLatLng().getLongitude()));

				latTextBox.setText(Double.toString(marker.getLatLng().getLatitude()));
			}
		});


		marker.addMarkerDragEndHandler(new MarkerDragEndHandler() {

			public void onDragEnd(MarkerDragEndEvent event) {

				if(exactPolygon != null) map.removeOverlay(exactPolygon);
				
				if(allowablePolygon != null) map.removeOverlay(allowablePolygon);
				
				exactPolygon = drawCircleFromRadius(marker.getLatLng(), 140, 40, "red");

				allowablePolygon = drawCircleFromRadius(marker.getLatLng(), 180, 40, "yellow");
								
				map.addOverlay(allowablePolygon);
				map.addOverlay(exactPolygon);
				



			}
		});


		map.addOverlay(marker);

		map.addOverlay(manMarker);

		map.setSize("800px", "600px");


		// Add an info window to highlight a point of interest
		map.getInfoWindow().open(marker,
				new InfoWindowContent("Please drag me to the center of the <b>kindgdom tower</b> <br> to define the checkin area"));


		// Add the map to the HTML host page

		return map;
	}

	private PolygonII drawCircleFromRadius(LatLng center, double radius,int nbOfPoints,String color) {

		LatLngBounds bounds = LatLngBounds.newInstance();
		LatLng[] circlePoints = new LatLng[nbOfPoints];

		double EARTH_RADIUS = 6371000;
		double d = radius / EARTH_RADIUS;
		double lat1 = Math.toRadians(center.getLatitude());
		double lng1 = Math.toRadians(center.getLongitude());

		double a = 0;
		double step = 360.0 / (double) nbOfPoints;

		for (int i = 0; i < nbOfPoints; i++) {

			double tc = Math.toRadians(a);
			double lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) + Math.cos(lat1) * Math.sin(d) * Math.cos(tc));
			double lng2 = lng1 + Math.atan2(Math.sin(tc) * Math.sin(d) * Math.cos(lat1), Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));

			LatLng point = LatLng.newInstance(Math.toDegrees(lat2), Math.toDegrees(lng2));
			circlePoints[i] = point;
			bounds.extend(point);
			a += step;
		}

		PolygonII circle = new PolygonII(circlePoints, "white", 0, 0, color,  0.4);

		return circle;
	}
	
	private PolygonII drawFromRadius(LatLng center, double radius,int nbOfPoints,String color) {

		LatLngBounds bounds = LatLngBounds.newInstance();
		LatLng[] circlePoints = new LatLng[nbOfPoints];

		double EARTH_RADIUS = 6371000;
		double d = radius / EARTH_RADIUS;
		double lat1 = Math.toRadians(center.getLatitude());
		double lng1 = Math.toRadians(center.getLongitude());

		double a = 0;
		double step = 360.0 / (double) nbOfPoints;

		for (int i = 0; i < nbOfPoints; i++) {

			double tc = Math.toRadians(a);
			double lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) + Math.cos(lat1) * Math.sin(d) * Math.cos(tc));
			double lng2 = lng1 + Math.atan2(Math.sin(tc) * Math.sin(d) * Math.cos(lat1), Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));

			LatLng point = LatLng.newInstance(Math.toDegrees(lat2), Math.toDegrees(lng2));
			circlePoints[i] = point;
			bounds.extend(point);
			a += step;
		}

		PolygonII circle = new PolygonII(circlePoints, "white", 0, 0, color, 0.3);

		return circle;
	}


	private class PolygonII extends Polygon { 
		
		public PolygonII(LatLng[] points) { 
		
			super(points);
			
		} 
		
		public PolygonII(LatLng[] points, String strokeColor , int strokeWeight, double strokeOpacity, String fillColor, double fillOpacity) { 
			super(points, strokeColor , strokeWeight, strokeOpacity, 
					fillColor, fillOpacity); 
		}
		
		public PolygonII(LatLng[] points, String strokeColor , int 
				strokeWeight, double strokeOpacity, String fillColor, double 
				fillOpacity, PolygonOptions options) { 
			super(points, strokeColor , strokeWeight, strokeOpacity, 
					fillColor, fillOpacity, options); 
		} 
		
		public PolygonII(JavaScriptObject jsoPeer) { 
			super(jsoPeer); 
		}
		
		public boolean contains(LatLng latLng) { 
		
			int j = 0; 
			boolean oddNodes = false; 
			double x = latLng.getLongitude(); 
			double y = latLng.getLatitude(); 
			for (int i = 0; i < getVertexCount(); i++) { 
				j++; 
				if (j == getVertexCount()) { 
					j = 0; 
				} 
				if (((getVertex(i).getLatitude() < y) && (getVertex 
						(j).getLatitude() >= y)) 
						|| ((getVertex(j).getLatitude() < y) && (getVertex 
								(i).getLatitude() >= y))) { 
					if (getVertex(i).getLongitude() + (y - getVertex 
							(i).getLatitude()) 
							/ (getVertex(j).getLatitude() - getVertex 
									(i).getLatitude()) 
									* (getVertex(j).getLongitude() - getVertex 
											(i).getLongitude()) < x) { 
						oddNodes = !oddNodes; 
					} 
				} 
			} 
			return oddNodes; 
		} 

	} 


}
